<?php
include_once 'Grid.class.php';

abstract class Base {

    protected $errorList; //so it gets passed down but as a private

    function __construct() {
        
    }

    public function Save() {
        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");
        $this->escape($grid);
        $this->validate();
        $classWithId = $className."Id";
        if (count($this->errorList) == 0)
            $this->$classWithId = $grid->InsertOneObject($this); //Sets the ID with the most recently inserted Object
        
        return count($this->errorList) == 0 ? true : false;
    }

    public function Update() {
        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");

        $this->escape($grid);
        $this->validate();
        if (count($this->errorList) == 0)
            $grid->UpdateOneObject($this);
        
        return count($this->errorList) == 0 ? true : false;
    }

    public function SetFromSession($sessionId) {
        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");
        $sql = "SELECT * FROM " . $className . " WHERE session='$sessionId'";
        $grid->ExecuteSQL($sql);
        $row = $grid->FetchNext();
        $grid->RowToObject($this, $row);
    }
    
    /**
     *  Checks to see if $foreignKey is a valid key from $referencedTable. 
     * @param type $referencedTable
     * @param type $foreignKey
     * @return boolean 
     */
    public function ValidForeignKey($referencedTable, $foreignKey)
    {
        $referencedTableId = $referencedTable."Id";
        $sql = "SELECT * FROM ".$referencedTable." WHERE ".$referencedTableId."='$foreignKey'";
        $grid = new Grid();
        $grid->ExecuteSQL($sql);
        return $grid->GetResultsCount() > 0;
    }

    /**
     * 
     * @param int $id
     * @return associative array
     */
    public function GetArray($id) {
        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");
        $grid->SelectOne($id);
        return $grid->FetchNext();
    }

    /**
     * Sets $this object
     * @param int $id - id of entity to fetch
     */
    public function Get($id) {
        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");
        $grid->SelectOne($id);
        $row = $grid->FetchNext();
        $grid->RowToObject($this, $row);
    }

    /**
     * 
     * @param $orderBy
     * @return a list of rows
     */
    public function GetList($orderBy = "", $col = "") {
        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");
        $grid->SelectAll($orderBy, $col);
        return $grid->FetchAll();
    }

    /**
     * - Deletes object from database. 
     * - Cleans up any Foreign Key restrictions as needed.
     */
    public function Delete() {

        $className = $this->GetClassName();
        $grid = new Grid($className, $className . "Id");
        $key = $className . "Id";
        
        $this->recursiveDelete($className, $this->$key); // Delete all rows that rely on $this pk
        $grid->DeleteOne($this->$key);
    }
    
    /**
     * Recurses through database deleting rows that are dependant on $tableName and $keyVal
     * @param string $tableName
     * @param type $keyVal 
     */
    private function recursiveDelete($tableName, $keyVal)
    {
        $sql = "SELECT i.TABLE_NAME, i.CONSTRAINT_NAME, k.REFERENCED_TABLE_NAME, k.REFERENCED_COLUMN_NAME 
                FROM information_schema.TABLE_CONSTRAINTS i 
                LEFT JOIN information_schema.KEY_COLUMN_USAGE k ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME 
                WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' 
                    AND i.TABLE_SCHEMA = DATABASE() 
                    AND k.REFERENCED_TABLE_NAME = '$tableName'"; //Find all tables that have a FK reference to $tableName
        
        $grid = new Grid();
        $grid->ExecuteSQL($sql);
        while($row = $grid->FetchNext())
        {
            $grid2 = new Grid();
            $referencingTable = $row["TABLE_NAME"];
            $referencedColumn = $tableName."Id";
            
            $sql2 = "SELECT * FROM $referencingTable WHERE $referencedColumn='$keyVal'";  // Find all the rows that have a foreign key restriction
            $grid2->ExecuteSQL($sql2);
            while($row2 = $grid2->FetchNext()) 
            {
                $this->recursiveDelete($referencingTable, $row2[$this->getTablePKColumnName($referencingTable)]);
            }
            
            $grid2->ExecuteSQL("DELETE FROM $referencingTable WHERE $referencedColumn='$keyVal'");
        }
    }
    private function getTablePKColumnName($tableName)
    {
        $sql = "SELECT k.column_name
FROM information_schema.table_constraints t
JOIN information_schema.key_column_usage k
USING(constraint_name,table_schema,table_name)
WHERE t.constraint_type='PRIMARY KEY'
  AND t.table_schema=DATABASE() 
  AND t.table_name='$tableName'";
        $grid = new Grid();
        $grid->ExecuteSQL($sql);
        $row = $grid->FetchNext();
        return $row["column_name"];
    }
    public function GetClassName() {
        $className = get_class($this);
        $className{0} = strtolower($className{0});
        return $className;
    }

    public function AddError($error) {
        $this->errorList[] = $error;
    }

    public function IsNum($val) {
        return is_numeric($val);
    }

    public function IsInt($val) {
        return is_int($val);
    }

    public function getErrorList() {
        if (count($this->errorList) > 0)
            return $this->formatErrorMessage($this->errorList);
        else
            return true;
    }

    protected function formatErrorMessage($message) {
        $fullMessage = "<ul>";
        foreach ($message as $m) {
            $fullMessage.="<li>" . $m . "</li>";
        }
        $fullMessage.="</ul>";
        return $fullMessage;
    }

    abstract protected function validate();

    abstract protected function escape($grid);
}

?>